//
//  UIControl+Extension.m
//  Button防止多次点击
//
//  Created by keisun on 2018/3/26.
//  Copyright © 2018年 keisun. All rights reserved.
//

#import "UIControl+Extension.h"
#import <objc/runtime.h>

//void *表示未确定类型指针，可以指向任何类型数据
static void *UIControl_eventInternalKey = "UIControl_eventInternalKey";
static void *UIControl_eventTimeKey = "UIControl_eventTimeKey";
@interface UIControl ()
//首次事件发生的时间
@property(nonatomic, assign)NSTimeInterval eventTime;
@end

@implementation UIControl (Extension)

-(void)setEventInternal:(NSTimeInterval)eventInternal{
    objc_setAssociatedObject(self, UIControl_eventInternalKey, @(eventInternal), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(NSTimeInterval)eventInternal{
    return [objc_getAssociatedObject(self, UIControl_eventInternalKey) doubleValue];
}

-(void)setEventTime:(NSTimeInterval)eventTime{
    objc_setAssociatedObject(self, UIControl_eventTimeKey, @(eventTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(NSTimeInterval)eventTime{
    return [objc_getAssociatedObject(self, UIControl_eventTimeKey) doubleValue];
}

//不管外面多少个button，initialize与load中打印结果是
/**
 2018-12-13 15:16:16.008132+0800 Button防止多次点击[17553:1319414] ===UIControl
 2018-12-13 15:16:16.008727+0800 Button防止多次点击[17553:1319414] ----UIControl
 2018-12-13 15:16:16.341998+0800 Button防止多次点击[17553:1319414] ===UIButton
 */

//这个主要用来与load作对比，同类名下，先执行initialize，再执行load
+(void)initialize{
    NSLog(@"===%@",self);//先打印UIControl，再打印UIButton。这个过程无论几个button只进行一次
}

+(void)load{
    NSLog(@"----%@", self);//无论几个button，有且只打印一次，即打印UIControl
    //获取实例方法
    Method systemMethod = class_getInstanceMethod([self class], @selector(sendAction:to:forEvent:));
    Method myMethod = class_getInstanceMethod([self class], @selector(gh_sendAction:to:forEvent:));
    //method_getTypeEncoding(systemMethod)打印：v40@0:8:16@24@32
    //[Type Encodings](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1)
        /*strcmp从左至右比较ASCII码，直到遇到不同字符或'\0'为止。若字符全相同，则相等。若出现不相同字符，以第一个字符的比较结果为准。
        s1<s2时，返回负数
        s1=s2，返回值=0
        s1>s2，返回正数
         */
    //判断方式也可以用 if(!class_addMethod([self class], @selector(sendAction:to:forEvent:), method_getImplementation(myMethod), method_getTypeEncoding(myMethod)))
    if (systemMethod && myMethod && strcmp(method_getTypeEncoding(systemMethod), method_getTypeEncoding(myMethod))==0) {
        method_exchangeImplementations(systemMethod, myMethod);
    }else{
        class_addMethod([self class], @selector(sendAction:to:forEvent:), method_getImplementation(myMethod), method_getTypeEncoding(myMethod));
    }
}

-(void)gh_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{
    
    //NSDate.date.timeIntervalSince1970表示当前的时间戳, self.eventTime上次记录的时间戳
    if (NSDate.date.timeIntervalSince1970 - self.eventTime< self.eventInternal){
        return;
    }
    
    if (self.eventInternal > 0) {
        self.eventTime = NSDate.date.timeIntervalSince1970;
    }
    [self gh_sendAction:action to:target forEvent:event];
}

@end
